package cn.yangliu.aspect;

import cn.yangliu.comm.BaseException;
import cn.yangliu.comm.entity.JsonResult;
import cn.yangliu.comm.tools.ReflectUtils;
import cn.yangliu.comm.tools.WebUtils;
import com.alibaba.fastjson.JSON;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.document.AbstractPdfView;
import org.springframework.web.servlet.view.document.AbstractXlsView;
import org.springframework.web.servlet.view.document.AbstractXlsxStreamingView;
import org.springframework.web.servlet.view.document.AbstractXlsxView;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.time.Duration;
import java.time.LocalTime;

/**
 * 作者 杨柳
 * 创建时间 2017-08-29 01:21
 */
@Component
@Aspect
@Order
public class RequestAspect extends AbstractAspect {
    @Pointcut("@annotation(org.springframework.web.bind.annotation.RequestMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.DeleteMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.PutMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.PostMapping)" +
            "||@annotation(org.springframework.web.bind.annotation.GetMapping)")
    public void advice() {
    }

    @Around("advice()")
    public Object logAspect(ProceedingJoinPoint joinPoint) throws Throwable {
        LocalTime start = LocalTime.now();
        Object obj = null;
        //判断是不是返回json的方法
        boolean isjson = checkReturnJson(joinPoint);
        // 获取当前调用的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        Class<?> clazz = method.getReturnType();
        if (isjson&& (clazz!=Void.class)&&clazz!=JsonResult.class){
            throw new ClassCastException(method.getName()+"返回值不允许为"+clazz);
        }
        try {
            obj = joinPoint.proceed();
        } catch (Throwable t) {
            if (isjson) { //返回json
                doRecord(t,joinPoint);
                JsonResult result = new JsonResult();
                result.setCode("900001");
                //如果是自定义异常
                if (t instanceof BaseException) {
                    result.setMsg(t.getMessage());
                } else {
                    result.setMsg("操作失败,系统错误");
                }
                obj = result;
            } else { //不返回json
                LocalTime end = LocalTime.now();
                Duration duration=Duration.between(start,end);
                doRecordParams(null,duration);
                throw t;
            }
        }

        //正常响应
        LocalTime end = LocalTime.now();
        Duration duration=Duration.between(start,end);
        doRecordParams(obj,duration);
        return obj;
    }

    private void doRecordParams(Object result,Duration duration) {
        String url = WebUtils.getRequest().getRequestURI();
        String host = WebUtils.getIp();
        HttpServletRequest request = WebUtils.getRequest();
        String params = "";
        //上传不记录参数
        if (!(request instanceof MultipartHttpServletRequest)){
            params = JSON.toJSONString(request.getParameterMap());
        }
        String method = WebUtils.getRequest().getMethod();
        StringBuilder sb = new StringBuilder("IP:{").append(host)
                .append("},请求:{").append(url).append("},方式:{")
                .append(method).append("},耗时:{").append(duration).append("},参数:").append(params)
                .append("响应:");
        if (result==null){
            result = "null";
        }
        //下载文档文件不记录返回值
        if (!checkExportView(result)){
            sb.append(JSON.toJSON(result));
        }
        logger.info(sb.toString());
        logger.info("完整请求:    "+WebUtils.getFullUrl());
    }

    private boolean checkExportView(Object result){
        if (result instanceof ModelAndView){
            ModelAndView mav = (ModelAndView) result;
            View view=mav.getView();
            if (view==null){
                return false;
            }
            boolean flag =ReflectUtils.isSubClassOrEquesClass(view.getClass(), AbstractPdfView.class)
                    ||ReflectUtils.isSubClassOrEquesClass(view.getClass(), AbstractXlsView.class)
                    ||ReflectUtils.isSubClassOrEquesClass(view.getClass(), AbstractXlsxView.class)
                    ||ReflectUtils.isSubClassOrEquesClass(view.getClass(), AbstractXlsxStreamingView.class);
            if (view!=null&&flag){
              return true;
            }else {
                return false;
            }
        }
        return false;
    }
}
